﻿using System;
using System.Collections.Generic;
using Autodesk.Revit.DB;
using YJKGeometryFuncs;
using YJKGeometryFuncs.CurveUtility;
using YJKPatternSign.StairsRoomPlanSign.ControlLayer;

namespace YJKPatternSign.StairsRoomPlanSign.ModelLayer
{
	public class WallElementPacker
	{
		public Wall UseWall
		{
			get
			{
				return this.m_useWall;
			}
			private set
			{
				this.m_useWall = value;
			}
		}

		public double WallWidth
		{
			get
			{
				return this.m_dWallWidth;
			}
			private set
			{
				this.m_dWallWidth = value;
			}
		}

		public RevitLinkInstance UseLinkInstance
		{
			get
			{
				return this.m_useLinkInstance;
			}
			private set
			{
				this.m_useLinkInstance = value;
			}
		}

		public int UseWallId
		{
			get
			{
				return this.m_nuseWallId;
			}
			private set
			{
				this.m_nuseWallId = value;
			}
		}

		public int UseLInkInstanceId
		{
			get
			{
				return this.m_nuseLInkInstanceId;
			}
			private set
			{
				this.m_nuseLInkInstanceId = value;
			}
		}

		public Curve OrgionLocationCurve
		{
			get
			{
				return this.m_orgionLocationCurve;
			}
			private set
			{
				this.m_orgionLocationCurve = value;
			}
		}

		public Curve UseMidCurve
		{
			get
			{
				return this.m_useMidCurve;
			}
			private set
			{
				this.m_useMidCurve = value;
			}
		}

		public List<Curve> LstOffestCurve
		{
			get
			{
				return this.m_lstOffestCurve;
			}
			private set
			{
				this.m_lstOffestCurve = value;
			}
		}

		public List<FamilyInstance> LstDoorsOnThisWall
		{
			get
			{
				return this.m_lstDoorsOnThisWall;
			}
			private set
			{
				this.m_lstDoorsOnThisWall = value;
			}
		}

		public List<FamilyInstance> LstWindowsOnThisWall
		{
			get
			{
				return this.m_lstWindowsOnThisWall;
			}
			private set
			{
				this.m_lstWindowsOnThisWall = value;
			}
		}

		public XYZ UseMidPoint
		{
			get
			{
				return this.m_useMidPoint;
			}
			private set
			{
				this.m_useMidPoint = value;
			}
		}

		public List<WallElementPacker> LstAllIntersectWallWithThis
		{
			get
			{
				return this.m_lstAllIntersectWallWithThis;
			}
			private set
			{
				this.m_lstAllIntersectWallWithThis = value;
			}
		}

		public WallDriectionKindEnum ThisWallIntersectionKind
		{
			get
			{
				return this.m_thisWallIntersectionKind;
			}
			set
			{
				this.m_thisWallIntersectionKind = value;
			}
		}

		public List<Curve> LstCurveIntersectionUse
		{
			get
			{
				return this.m_lstCurveIntersectionUse;
			}
			private set
			{
				this.m_lstCurveIntersectionUse = value;
			}
		}

		public override bool Equals(object obj)
		{
			if (!(obj is WallElementPacker))
			{
				return false;
			}
			WallElementPacker wallElementPacker = obj as WallElementPacker;
			if (wallElementPacker != null)
			{
				return wallElementPacker.UseWallId == this.UseWallId && wallElementPacker.UseLInkInstanceId == this.UseLInkInstanceId;
			}
			return base.Equals(obj);
		}

		public override int GetHashCode()
		{
			return base.GetHashCode();
		}

		public WallElementPacker(Wall inputWall, double useZ, RevitLinkInstance inputLinkInstance = null)
		{
			this.UseWall = inputWall;
			this.UseWallId = this.UseWall.Id.IntegerValue;
			this.UseLinkInstance = inputLinkInstance;
			this.m_dWallWidth = this.UseWall.Width;
			this.m_dUseZ = useZ;
			if (this.UseLinkInstance != null)
			{
				this.m_useTransform = this.UseLinkInstance.GetTotalTransform();
				this.UseLInkInstanceId = this.UseLinkInstance.Id.IntegerValue;
			}
			this.OrgionLocationCurve = (this.UseWall.Location as LocationCurve).Curve;
			this.UseMidCurve = this.OrgionLocationCurve.Clone();
			if (this.m_useTransform != null)
			{
				this.UseMidCurve = this.UseMidCurve.CreateTransformed(this.m_useTransform);
			}
			this.UseMidCurve = CurveUtility.TransformCurveAtZAixs(this.UseMidCurve, useZ, true);
			this.UseMidPoint = this.UseMidCurve.Evaluate(0.5, true);
			this.LstOffestCurve.Add(CurveUtility.CreateOffsetCurve(this.UseMidCurve, 0.5 * this.m_dWallWidth));
			this.LstOffestCurve.Add(CurveUtility.CreateOffsetCurve(this.UseMidCurve, -0.5 * this.m_dWallWidth));
			this.LstCurveIntersectionUse.AddRange(this.LstOffestCurve);
		}

		public void AddFamilyInstance(FamilyInstance input)
		{
            if (input.Category.Id.IntegerValue == (int)StaticResource.UseDoorCategory)
			{
				this.LstDoorsOnThisWall.Add(input);
				return;
			}
            if (input.Category.Id.IntegerValue == (int)StaticResource.UseWindowCategory)
			{
				this.LstWindowsOnThisWall.Add(input);
			}
		}

		public bool IfThisWallIsAtDriectionEnd(XYZ useDriection, double useLength, double tolerance, List<WallElementPacker> allInPut)
		{
			XYZ xyz = this.UseMidPoint.Add(useDriection.Multiply(useLength));
			Line line = Line.CreateBound(this.UseMidPoint, xyz);
			bool result = true;
			if (this.IfthisCurveDirectionParallelGoalDriection(useDriection, tolerance))
			{
				return false;
			}
			foreach (WallElementPacker wallElementPacker in allInPut)
			{
				IntersectionResultArray intersectionResultArray;
                if (!wallElementPacker.Equals(this) && !wallElementPacker.IfthisCurveDirectionParallelGoalDriection(useDriection, tolerance) && (wallElementPacker.ThisWallIntersectionKind != WallDriectionKindEnum.Other || wallElementPacker.UseMidCurve.Length >= 0.3 * this.UseMidCurve.Length) && (int)wallElementPacker.UseMidCurve.Intersect(line, out intersectionResultArray) == 8)
				{
					result = false;
					break;
				}
			}
			return result;
		}

		public void AddOneIntersectionWall(WallElementPacker input)
		{
			if (!this.LstAllIntersectWallWithThis.Contains(input))
			{
				this.LstAllIntersectWallWithThis.Add(input);
			}
		}

		public void SetCurveMidPoint(BoundingBoxPakcer useBoundingBox)
		{
			this.UseMidPoint = Utility.GetCurveMidPointInBounding(this.UseMidCurve, useBoundingBox, this.m_dUseZ, out this.m_useMidCurve);
		}

		public bool IfInputWallIntersectionWithThis(WallElementPacker input)
		{
			if (input.Equals(this))
			{
				return false;
			}
			bool flag = false;
			foreach (Curve curve in this.LstCurveIntersectionUse)
			{
				foreach (Curve curve2 in input.LstCurveIntersectionUse)
				{
                    if ((int)curve.Intersect(curve2) == 8)
					{
						flag = true;
						break;
					}
				}
				if (flag)
				{
					break;
				}
			}
			if (!flag)
			{
				Curve curve3 = null;
				IntersectionResultArray intersectionResultArray = null;
				foreach (Curve curve4 in this.LstCurveIntersectionUse)
				{
					curve3 = curve4.Clone();
					curve3.MakeUnbound();
					foreach (Curve curve5 in input.LstCurveIntersectionUse)
					{
						Curve curve6 = curve5.Clone();
						curve6.MakeUnbound();
                        if ((int)curve3.Intersect(curve6, out intersectionResultArray) == 8)
						{
							using (List<ColumnPacker>.Enumerator enumerator3 = SignManger.ThisStairPlandDataPacker.LstColumnPackers.GetEnumerator())
							{
								while (enumerator3.MoveNext())
								{
									if (enumerator3.Current.IfTwoWallIntersectionInThis(intersectionResultArray.get_Item(0).XYZPoint, this, input))
									{
										flag = true;
										break;
									}
								}
							}
						}
						if (flag)
						{
							break;
						}
					}
					if (flag)
					{
						break;
					}
				}
			}
			return flag;
		}

		public List<XYZ> MakeAllDimisionPointOneMidCurve(XYZ inputDriection, double tolerance)
		{
			List<XYZ> list = new List<XYZ>();
			Curve baseCurve = this.UseMidCurve.Clone();
			Transform useTransform = this.m_useTransform;
			foreach (FamilyInstance inputFamiylInstance in this.LstDoorsOnThisWall)
			{
				list.AddRange(this.GetAFamilyInstanceWidthByParam(baseCurve, inputFamiylInstance, useTransform));
			}
			foreach (FamilyInstance inputFamiylInstance2 in this.LstWindowsOnThisWall)
			{
				list.AddRange(this.GetAFamilyInstanceWidthByParam(baseCurve, inputFamiylInstance2, useTransform));
			}
			foreach (WallElementPacker wallElementPacker in this.LstAllIntersectWallWithThis)
			{
				if (wallElementPacker.ThisWallIntersectionKind != WallDriectionKindEnum.Normal || (!(wallElementPacker.UseMidCurve as Line).Direction.IsAlmostEqualTo(inputDriection, tolerance) && !(wallElementPacker.UseMidCurve as Line).Direction.IsAlmostEqualTo(-inputDriection, tolerance)))
				{
					list.AddRange(this.GetAIntersectionWidth(wallElementPacker));
				}
			}
			return list;
		}

		private bool IfthisCurveDirectionParallelGoalDriection(XYZ useDriection, double tolerance)
		{
			return this.UseMidCurve is Line && ((this.UseMidCurve as Line).Direction.IsAlmostEqualTo(useDriection, tolerance) || (this.UseMidCurve as Line).Direction.IsAlmostEqualTo(-useDriection, tolerance));
		}

		private List<XYZ> GetAIntersectionWidth(WallElementPacker inputWall)
		{
			List<XYZ> list = new List<XYZ>();
			IntersectionResultArray inputResutlArray = null;
			List<Curve> list2 = new List<Curve>();
			WallDriectionKindEnum thisWallIntersectionKind = inputWall.ThisWallIntersectionKind;
			SetComparisonResult setComparisonResult;
			if (thisWallIntersectionKind != WallDriectionKindEnum.Normal)
			{
				if (thisWallIntersectionKind != WallDriectionKindEnum.Other)
				{
					return list;
				}
			}
			else
			{
				foreach (Curve curve in inputWall.LstCurveIntersectionUse)
				{
					list2.Add(curve.Clone());
				}
				for (int i = 0; i < list2.Count; i++)
				{
					list2[i].MakeUnbound();
				}
				foreach (Curve curve2 in list2)
				{
					Curve curve3 = this.UseMidCurve.Clone();
					curve3.MakeUnbound();
                    setComparisonResult = curve3.Intersect(curve2, out inputResutlArray);
					if (setComparisonResult == SetComparisonResult.Overlap)
					{
						XYZ anearIntersectionPoint = this.GetANearIntersectionPoint(this.UseMidCurve, inputResutlArray);
						if (anearIntersectionPoint != null)
						{
							list.Add(anearIntersectionPoint);
						}
					}
				}
				if (list.Count >= 2)
				{
					return list;
				}
				list.Clear();
				using (List<Curve>.Enumerator enumerator = this.LstCurveIntersectionUse.GetEnumerator())
				{
					while (enumerator.MoveNext())
					{
						Curve curve4 = enumerator.Current;
						foreach (Curve curve5 in inputWall.LstCurveIntersectionUse)
						{
							Curve curve6 = curve5.Clone();
							curve6.MakeUnbound();
							setComparisonResult = curve4.Intersect(curve6, out inputResutlArray);
							if (setComparisonResult == SetComparisonResult.Overlap)
							{
								XYZ anearIntersectionPoint = this.GetANearIntersectionPoint(curve5, inputResutlArray);
								if (anearIntersectionPoint != null)
								{
									list.Add(anearIntersectionPoint);
								}
							}
						}
					}
					return list;
				}
			}
			this.CalculateMidIntersectionPoint(inputWall, list, out setComparisonResult, out inputResutlArray);
			return list;
		}

		private void CalculateMidIntersectionPoint(WallElementPacker inputWall, List<XYZ> returnValue, out SetComparisonResult tempResult, out IntersectionResultArray tempIntersectionResultArray)
		{
            tempResult = this.UseMidCurve.Intersect(inputWall.UseMidCurve, out tempIntersectionResultArray);
			if ((int)tempResult == 8)
			{
				returnValue.Add(tempIntersectionResultArray.get_Item(0).XYZPoint);
			}
		}

		private List<XYZ> GetAFamilyInstanceWidthByParam(Curve baseCurve, FamilyInstance inputFamiylInstance, Transform useTransForm = null)
		{
			List<XYZ> list = new List<XYZ>();
			Curve curve = baseCurve.Clone();
			double length = baseCurve.Length;
			double num = baseCurve.GetEndParameter(1) - baseCurve.GetEndParameter(0);
			XYZ xyz = (inputFamiylInstance.Location as LocationPoint).Point;
			if (useTransForm != null)
			{
				xyz = Geometry.TransformPoint(xyz, useTransForm);
			}
			curve.MakeUnbound();
			double parameter = curve.Project(xyz).Parameter;
			xyz = curve.Project(xyz).XYZPoint;
			Parameter parameter2 = inputFamiylInstance.Symbol.get_Parameter(StaticResource.UseWidthParam);
			if (parameter2 != null)
			{
				double num2 = parameter2.AsDouble();
				num2 *= 0.5;
				double num3 = parameter - num2 * num / length;
				double num4 = parameter + num2 * num / length;
				list.Add(curve.Evaluate(num3, false));
				list.Add(curve.Evaluate(num4, false));
			}
			return list;
		}

		private XYZ GetANearIntersectionPoint(Curve baseCurve, IntersectionResultArray inputResutlArray)
		{
			XYZ result = null;
			double num = double.MaxValue;
			XYZ xyz = baseCurve.Evaluate(0.5, true);
			foreach (object obj in inputResutlArray)
			{
				IntersectionResult intersectionResult = (IntersectionResult)obj;
				if (intersectionResult.XYZPoint.DistanceTo(xyz) < num)
				{
					num = intersectionResult.XYZPoint.DistanceTo(xyz);
					result = intersectionResult.XYZPoint;
				}
			}
			return result;
		}

		private Wall m_useWall;

		private double m_dWallWidth;

		private RevitLinkInstance m_useLinkInstance;

		private Transform m_useTransform;

		private int m_nuseWallId = -1;

		private int m_nuseLInkInstanceId = -1;

		private double m_dUseZ;

		private Curve m_orgionLocationCurve;

		private Curve m_useMidCurve;

		private List<Curve> m_lstOffestCurve = new List<Curve>();

		private List<FamilyInstance> m_lstDoorsOnThisWall = new List<FamilyInstance>();

		private List<FamilyInstance> m_lstWindowsOnThisWall = new List<FamilyInstance>();

		private List<Curve> m_lstCurveIntersectionUse = new List<Curve>();

		private WallDriectionKindEnum m_thisWallIntersectionKind;

		private XYZ m_useMidPoint;

		private List<WallElementPacker> m_lstAllIntersectWallWithThis = new List<WallElementPacker>();
	}
}
